package pfq.demo.java;

/**
 * 父子类间代码执行的先后顺序：
 * 1. 子类会继承父类的非private的属性和方法
 * 2.1 不会继承构造函数，子类会且必须调用父类的构造函数，并分为显式调用和隐式调用两种情况；如果父类没有定义构造函数或者定义了无参构造函数，则在子类的构造函数中就没必要显式调用父类的构造函数了，因为子类会默认调用父类的无参构造函数，也就是隐式调用；而如果父类定义了带参数的构造函数，则在子类的构造函数中要显示调用父类的构造函数，因为子类自己不知道应该调用父类的哪个构造函数。
 * 2.2 所以在创建一个子类对象的时候，会发现调用了子类的父类构造函数，如果父类还有父类，同样也会调用父类的构造函数
 * 3. 子类有父类同名同参的方法叫覆写，这是父子间的多态
 * 4. 一个类（跟父子类无关）有多个同名不同参（参数类型不同、个数不同、顺序不同）的方法叫重载，这是类内部的多态
 */
public class FatherSonClass {

    public static void main(String[] args) {

        TaskC taskC = new TaskC("abc");
        // 执行的是a(TaskB taskB)这个方法，虽然TaskB和TaskA都是TaskC的父类，但Java会优先执行TaskC的直接父类
        taskC.a(new TaskC());


    }

    static class TaskA {
        static {
            System.out.println("TaskA static code block");
        }

        TaskA() {
            System.out.println("TaskA");
        }

        public void a() {
            System.out.println("TaskA a");
        }
    }

    static class TaskB extends TaskA {

        static {
            System.out.println("TaskB static code block");
        }

        TaskB(String abc) {
            // 会默认隐式调用父类的无参构造函数
            System.out.println("TaskB abc");
        }

        public void a() {
            System.out.println("TaskB a 覆写");
        }

        public void a(String a) {
            System.out.println("TaskB a 重载");
        }

        public void a(int a) {
            System.out.println("TaskB a 重载");
        }

        public void a(int a, String b) {
            System.out.println("TaskB a 重载");
        }

        public void a(String a, int b) {
            System.out.println("TaskB a 重载");
        }

    }

    static class TaskC extends TaskB {

        // 因为静态方法或属性是在类加载的时候在内存中就已经分配好了，所以会优先执行
        // 此处TaskA实例被定义成了static，所以会优先执行，也就是会创建TaskA对象，并执行TaskA的构造函数
        static TaskA taskA = new TaskA();

        // 静态方法的执行顺序按照定义的优先顺序
        static {
            System.out.println("TaskC static code block");
        }


        // 构造代码块只优先于自己的构造方法
        {
            System.out.println("code block");
        }

        TaskC() {
            // 因为父类只定义了带参构造函数，所以只能显示调用了，因为编译器不知道父类定义了什么构造函数
            super("");
            System.out.println("TaskC");
        }

        TaskC(String args) {
            // 因为父类只定义了带参构造函数，所以只能显示调用了，因为编译器不知道父类定义了什么构造函数
            super("");
            System.out.println("TaskC 含参构造函数");
        }

        public void a() {
            System.out.println("TaskC a 覆写");
        }

        public void a(TaskA taskA) {
            System.out.println("TaskC a 重载 TaskA");
        }

        public void a(TaskB taskB) {
            System.out.println("TaskC a 重载 TaskB");
        }
    }

}
